using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Web.UI.Design;
using PHSRAG.Insight21.CDS;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.ClinicalTrials;
using System.Text;

namespace PHSRAG.Insight21.InsightWebControls.ClinicalTrials
{
    /// <summary>
    /// The Budget Task Control is used to provide a user interface for a single Budget Task.
    /// </summary>
    [ToolboxData("<{0}:BudgetTaskControl runat=server></{0}:BudgetTaskControl>"), Designer(typeof(BudgetTaskControlDesigner))]
    public class BudgetTaskControl : System.Web.UI.WebControls.TableRow, INamingContainer
    {
        #region Instance Variables
        private BudgetTask budgetTask;
        private Budget budget;
//        private TableRow tr;
        private DropDownList personList;
        private DropDownList tasksList;
        private CheckBox applyOverhead;
        private CheckBox delete;
        private CheckBox overRide;
        private CheckBox selectAllReq;
        private CheckBox selectAllSOC;
        private TextBox otherTaskText;
        private TextBox taskCost;
        private TextBox hours;
        private bool otherTask;
        private ArrayList requiredList = new ArrayList();
        private ArrayList standardOfCareList = new ArrayList();
        private RequiredFieldValidator descriptionValidator;
        private RequiredFieldValidator hoursRequiredValidator;
        private RangeValidator personValidator;
        private RegularExpressionValidator hoursFormatValidator;
        private RegularExpressionValidator taskCostFormatValidator;
        private RequiredFieldValidator taskCostRequiredValidator;
        #endregion

        #region Constants
        private const int columnsBeforeVisits = 7;
        private const string naPerson = "N/A";
        #endregion

        #region Public Methods
        /// <summary>
        /// Returns an indicator showing whether the task is required for a given visit
        /// </summary>
        /// <param name="index">Visit index</param>
        /// <returns>bool</returns>
        public bool GetRequired(int index)
        {
            return ((CheckBox)requiredList[index]).Checked;
        }

        /// <summary>
        /// Returns an indicator showing whether the task is part of the standard of care for a given visit
        /// </summary>
        /// <param name="index"></param>
        /// <returns>bool</returns>
        public bool GetStandardOfCare(int index)
        {
            return ((CheckBox)standardOfCareList[index]).Checked;
        }

        /// <summary>
        /// Returns the task cost for a given visit
        /// </summary>
        /// <param name="index">Visit index</param>
        /// <returns>decimal</returns>
        public decimal GetTaskCost(int index)
        {
            // The task cost is non-zero if the the task is required and not part of the
            // standard of care for a particular visit.
            decimal taskCost = 0.00M;
            if (GetRequired(index) && !GetStandardOfCare(index))
            {
                // If overhead is to be applied, we apply it here
                if (!String.IsNullOrEmpty(this.taskCost.Text))
                {
                    taskCost = decimal.Parse(this.taskCost.Text);
                    if (ApplyOverhead)
                    {
                        taskCost *= 1 + budget.OverheadRate;
                    }
                }
            }
            return taskCost;
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Apply overhead indicator
        /// </summary>
        public bool ApplyOverhead
        {
            get
            {
                return applyOverhead.Checked;
            }
        }

        /// <summary>
        /// Override the standard calculation indicator
        /// </summary>
        public bool OverRide
        {
            get
            {
                return overRide.Checked;
            }
        }

        /// <summary>
        /// Delete indicator
        /// </summary>
        public bool Delete
        {
            get
            {
                return delete.Checked;
            }
        }

        /// <summary>
        /// Staff Id
        /// </summary>
        public string StaffId
        {
            get
            {
                return personList.SelectedValue;
            }
        }

        /// <summary>
        /// Task Code
        /// </summary>
        public string TaskCode
        {
            get
            {
                return tasksList.SelectedValue;
            }
        }

        /// <summary>
        /// Other Task Text
        /// </summary>
        public string OtherTaskText
        {
            get
            {
                return otherTaskText.Text;
            }
        }

        /// <summary>
        /// Task Cost
        /// </summary>
        public string TaskCost
        {
            get
            {
                return taskCost.Text;
            }
        }

        /// <summary>
        /// Hours
        /// </summary>
        public string Hours
        {
            get
            {
                return hours.Text;
            }
        }
        #endregion

        #region Constructor
        /// <summary>
        /// Sets the private Budget Task member from the passed in parameter
        /// </summary>
        /// <param name="budgetTask">Current Task</param>
        /// <param name="otherTask">Other Task</param>   
        public BudgetTaskControl(BudgetTask budgetTask, bool otherTask)
        {
            this.budgetTask = budgetTask;
            this.otherTask = otherTask;
        }
        #endregion

        #region Overrides
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            EnsureChildControls();
        }

        /// <summary>
        /// Runs upon loading of the control
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            //         EnsureChildControls( );
        }

        /// <summary>
        /// Creates all child controls, applying styles, setting values, and binding validation
        /// </summary>
        protected override void CreateChildControls()
        {
            descriptionValidator = new RequiredFieldValidator();
            personValidator = new RangeValidator();
            hoursFormatValidator = new RegularExpressionValidator();
            hoursRequiredValidator = new RequiredFieldValidator();
            taskCostRequiredValidator = new RequiredFieldValidator();
            taskCostFormatValidator = new RegularExpressionValidator();

            budget = (Budget)((Policy.ICachePolicy)Page.Session[Policy.Names.CachePolicyKey]).GetCachedObject(Budget.CacheKey);
            tasksList = new DropDownList();
            tasksList.ID = "tasksList";

            // Load person dropdown
            personList = new DropDownList();
            personList.ID = "personList";
            personList.DataTextField = "StudyStaffRoleMeaning";
            personList.DataValueField = "Id";
            personList.DataSource = budget.BudgetStaff;
            personList.DataBind();
            //            personList.Items.Insert(0, new ListItem(naPerson, "1"));

            if (budgetTask.BudgetStaffId != 0)
            {
                personList.SelectedValue = budgetTask.BudgetStaffId.ToString();
            }
            else
            {
                personList.Items.Insert(0, new ListItem("", "0"));
            }

            personList.AutoPostBack = true;
            personList.SelectedIndexChanged += new EventHandler(OnPersonChanged);

            applyOverhead = new CheckBox();
            applyOverhead.ID = "applyOverhead";
            applyOverhead.Checked = budgetTask.ApplyOverhead;

            TableCell tdOverRide = new TableCell();
            overRide = new CheckBox();
            tdOverRide.Controls.Add(overRide);
            overRide.ID = "overRide";
            overRide.Checked = budgetTask.OverRideRate;
            overRide.CheckedChanged += new EventHandler(OnOverRideChanged);
            overRide.AutoPostBack = true;

            delete = new CheckBox();

            selectAllReq = new CheckBox();
            selectAllReq.AutoPostBack = true;
            selectAllReq.CheckedChanged += new EventHandler(OnSelectAllChanged);

            selectAllSOC = new CheckBox();
            selectAllSOC.AutoPostBack = true;
            selectAllSOC.CheckedChanged += new EventHandler(OnSelectAllChanged);

            hours = new TextBox();
            hours.ID = "hours";
            hours.CssClass = "TaskControlSmallWidth";
            hours.AutoPostBack = false;
            otherTaskText = new TextBox();
            otherTaskText.ID = "otherTaskText";
            otherTaskText.Text = budgetTask.OtherTaskText;
            taskCost = new TextBox();
            taskCost.ID = "taskCost";
            taskCost.CssClass = "TaskControlSmallWidth";
            taskCost.Text = budgetTask.TaskCost;
            taskCost.AutoPostBack = true;

            System.Web.HttpApplicationState app = System.Web.HttpContext.Current.Application;
            ICachePolicy cachePolicy = (ICachePolicy)app[Policy.Names.ApplicationCachePolicyKey];
            CDS.RefCodes refCodes = (RefCodes)cachePolicy.GetCachedObject(RefCodes.CacheKey);

            if (!otherTask)
            {
                // Load tasks dropdown from ref codes
                ArrayList budgetTaskCodes = refCodes.GetRefCodes("ClinicalTrialBudgetTask");
                tasksList.DataTextField = "Meaning";
                tasksList.DataValueField = "Code";
                tasksList.DataSource = budgetTaskCodes;
                tasksList.DataBind();
                if (!String.IsNullOrEmpty(budgetTask.BudgetTaskCode))
                {
                    tasksList.SelectedValue = budgetTask.BudgetTaskCode;
                    OnSelectedIndexChanged(this, EventArgs.Empty);
                }
                else
                {
                    tasksList.Items.Insert(0, new ListItem("-- Select Task --", ""));
                    taskCost.Enabled = false;
                }

                tasksList.AutoPostBack = true;
                tasksList.SelectedIndexChanged += new EventHandler(OnSelectedIndexChanged);
                otherTaskText.Visible = false;

                descriptionValidator.ErrorMessage = "Task is required.";
                descriptionValidator.Display = ValidatorDisplay.None;
                descriptionValidator.ControlToValidate = tasksList.ID;
            }
            else
            {
                if (budgetTask.Id != 0)
                {
                    hours.Text = budgetTask.Hours;
                    taskCost.Text = budgetTask.TaskCost;
                }
                otherTaskText.CssClass = "ExpandControlWithCheckbox";
                otherTaskText.ToolTip = "Enter \"Other Cost\" Description";
                tasksList.Visible = false;
                taskCost.Enabled = false;

                descriptionValidator.ErrorMessage = "Task is required.";
                descriptionValidator.Display = ValidatorDisplay.None;
                descriptionValidator.ControlToValidate = otherTaskText.ID;
            }

            // Setup validators
            personValidator.ErrorMessage = "Person is required.";
            personValidator.MinimumValue = "1";
            personValidator.MaximumValue = int.MaxValue.ToString();
            personValidator.Type = ValidationDataType.Integer;
            personValidator.Display = ValidatorDisplay.None;
            personValidator.ControlToValidate = personList.ID;

            hoursFormatValidator.ErrorMessage = "Hours must be a valid number up to 2 decimal places.";
            hoursFormatValidator.Display = ValidatorDisplay.None;
            hoursFormatValidator.ControlToValidate = hours.ID;
            hoursFormatValidator.ValidationExpression = @"^(\+|-)?\d{0,6}(\.\d{1,2})?$";

            hoursRequiredValidator.ErrorMessage = "Hours are required.";
            hoursRequiredValidator.Display = ValidatorDisplay.None;
            hoursRequiredValidator.ControlToValidate = hours.ID;

            taskCostFormatValidator.ErrorMessage = "Task cost must be a valid dollar amount.";
            taskCostFormatValidator.Display = ValidatorDisplay.None;
            taskCostFormatValidator.ControlToValidate = taskCost.ID;
            taskCostFormatValidator.ValidationExpression = @"\d+\.{0,1}\d{0,2}";

            taskCostRequiredValidator.ErrorMessage = "Task Cost is required.";
            taskCostRequiredValidator.Display = ValidatorDisplay.None;
            taskCostRequiredValidator.ControlToValidate = taskCost.ID;

            //tr = new TableRow();
            TableCell tdDescription = new TableCell();
            tdDescription.Controls.Add(descriptionValidator);
            tdDescription.Controls.Add(applyOverhead);
            tdDescription.Controls.Add(tasksList);
            tdDescription.Controls.Add(otherTaskText);

            TableCell tdHours = new TableCell();
            tdHours.Controls.Add(hoursFormatValidator);
            tdHours.Controls.Add(hoursRequiredValidator);
            tdHours.Controls.Add(hours);

            TableCell tdPerson = new TableCell();
            tdPerson.Controls.Add(personValidator);
            tdPerson.Controls.Add(personList);

            TableCell tdCost = new TableCell();
            tdCost.Controls.Add(taskCostFormatValidator);
            tdCost.Controls.Add(taskCostRequiredValidator);
            tdCost.Controls.Add(taskCost);

            TableCell tdSelectAll = new TableCell();
            tdSelectAll.Controls.Add(selectAllReq);
            tdSelectAll.Controls.Add(selectAllSOC);

            Cells.Add(tdDescription);
            Cells.Add(tdHours);
            Cells.Add(tdPerson);
            Cells.Add(tdOverRide);
            Cells.Add(tdCost);

            TableCell tdDelete = new TableCell();
            tdDelete.Controls.Add(delete);
            Cells.Add(tdDelete);

            Cells.Add(tdSelectAll);

            // Setup the controls for each budget milestone visit (checkboxes and cost labels)
            BudgetMilestoneVisits budgetMilestoneVisits = budgetTask.BudgetMilestoneVisits;
            for (int i = 0; i < budgetMilestoneVisits.Count; ++i)
            {
                BudgetMilestoneVisit budgetMilestoneVisit = budgetMilestoneVisits[i];
                TableCell BMV = new TableCell();
                CheckBox required = new CheckBox();
                required.ID = string.Format("required{0}", i);
                required.Checked = budgetMilestoneVisit.Required;
                requiredList.Add(required);
                CheckBox standardOfCare = new CheckBox();
                standardOfCare.ID = string.Format("standardOfCare{0}", i);
                standardOfCare.Checked = budgetMilestoneVisit.StandardOfCare;
                standardOfCareList.Add(standardOfCare);
                HtmlGenericControl span = new HtmlGenericControl();
                span.Attributes["class"] = "Cost";
                Label cost = new Label();
                cost.ID = string.Format("cost{0}", i);
                span.Controls.Add(cost);
                BMV.Controls.Add(required);
                BMV.Controls.Add(standardOfCare);
                BMV.Controls.Add(span);
                Cells.Add(BMV);
            }

            TableCell tdTotalPerPatient = new TableCell();
            Cells.Add(tdTotalPerPatient);

        }

        /// <summary>
        /// Used to set the task costs just before rendering, because task id may have
        /// changed upon postback.
        /// </summary>
        protected override void OnPreRender(EventArgs e)
        {
            int visitsCount = budgetTask.BudgetMilestoneVisits.Count;
            decimal totalCost = 0;
            for (int i = columnsBeforeVisits; i < visitsCount + columnsBeforeVisits; ++i)
            {
                TableCell BMV = Cells[i];
                Label cost = (Label)BMV.Controls[2].Controls[0];
                decimal taskCost = GetTaskCost(i - columnsBeforeVisits);
                cost.Text = taskCost.ToString("c");
                totalCost += taskCost;
                BudgetStaffList budgetStaffForToolTip = budget.BudgetStaff;
                BudgetStaff staffPersonForToolTip = budgetStaffForToolTip.GetStaffById(Int32.Parse(personList.SelectedValue));
                if (!String.IsNullOrEmpty(this.budgetTask.OtherTaskText))
                {
                    if (personList.SelectedIndex != 0)
                    {
                        string tooltip = "header=[Task Description | Person] body=[" + otherTaskText.Text + " | " + staffPersonForToolTip.StudyStaffRoleMeaning.ToString() + "]";
                        BMV.Attributes.Add("Title", tooltip);
                    }
                }
                else
                {
                    if (personList.SelectedIndex != 0)
                    {
                        string tooltip = "header=[Task Description | Person] body=[" + tasksList.SelectedItem.ToString() + " | " + staffPersonForToolTip.StudyStaffRoleMeaning.ToString() + "]";
                        BMV.Attributes.Add("Title", tooltip);
                    }
                }


            }
            Cells[visitsCount + columnsBeforeVisits].Text = totalCost.ToString("c");
            Cells[visitsCount + columnsBeforeVisits].CssClass = "Label";

            if (OverRide)
            {
                if (!String.IsNullOrEmpty(this.taskCost.Text))
                {
                    taskCost.Enabled = true;
                    taskCost.Text = decimal.Parse(this.taskCost.Text).ToString("f");
                }

                // if "N/A" is selected, overRide and hours both need to be grayed out.
                // note this is within the "if (OverRide) ..." block because overRide should
                // always be checked if "N/A" is selected.
                if (personList.SelectedItem.Text == naPerson)
                {
                    overRide.Enabled = false;
                    hours.Text = "0.00";
                    hours.Enabled = false;
                }
            }
            else
            {
                BudgetStaffList budgetStaff = budget.BudgetStaff;
                BudgetStaff staff = budgetStaff.GetStaffById(Int32.Parse(personList.SelectedValue));
                if (!String.IsNullOrEmpty(hours.Text) && staff != null)
                {
                    taskCost.Enabled = false;
                    decimal cost = decimal.Parse(staff.Rate) * decimal.Parse(hours.Text);
                    taskCost.Text = cost.ToString("f");
                }
            }
            base.OnPreRender(e);
        }
        #endregion

        #region Event Handlers
        /// <summary>
        /// Event handler to process changes to the selected task.  Used here to 
        /// set the hours and task cost.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnSelectedIndexChanged(object sender, EventArgs e)
        {
            // Set the default hours
            System.Web.HttpApplicationState app = System.Web.HttpContext.Current.Application;
            ICachePolicy cachePolicy = (ICachePolicy)app[Policy.Names.ApplicationCachePolicyKey];
            CDS.RefCodes refCodes = (RefCodes)cachePolicy.GetCachedObject(RefCodes.CacheKey);
            RefCode refCode = refCodes.GetRefCode("ClinicalTrialBudgetTask", tasksList.SelectedValue);
            hours.Text = refCode.Attributes["Hours"].ToString();
            if (budgetTask.Id != 0)
            {
                hours.Text = budgetTask.Hours;
            }
            // Remove the Select task item
            tasksList.Items.Remove(new ListItem("-- Select Task --", ""));
        }
        #endregion

        private void OnPersonChanged(object sender, EventArgs e)
        {
            // selecting "N/A" allows tasks to be created that do not
            // require a specific person to manage (e.g., parking costs)
            if (personList.SelectedItem.Text == naPerson)
            {
                hours.Text = "0.00";
                hours.Enabled = false;
                overRide.Checked = true;
                overRide.Enabled = false;
                taskCost.Enabled = true;
            }

            else
            {
                // reset any side effects from selecting "N/A"
                hours.Enabled = true;
                overRide.Enabled = true;

                // Set the default task cost
                if (!String.IsNullOrEmpty(hours.Text) && personList.SelectedValue.ToString() != "0")
                {
                    BudgetStaffList budgetStaff = budget.BudgetStaff;
                    BudgetStaff staff = budgetStaff.GetStaffById(Int32.Parse(personList.SelectedValue));
                    if (!OverRide)
                    {
                        decimal cost = decimal.Parse(staff.Rate) * decimal.Parse(hours.Text);
                        taskCost.Text = cost.ToString("f");
                    }
                }
            }
        }

        /// <summary>
        /// On the event that the override checkbox is checked the task cost textbox 
        /// will be enabled and for unchecked disabled 
        /// </summary>
        private void OnOverRideChanged(object sender, EventArgs e)
        {
            taskCost.Enabled = OverRide;
        }

        private void OnSelectAllChanged(object sender, EventArgs e)
        {
            if (selectAllSOC.Checked)
            {
                for (int i = 0; i < standardOfCareList.Count; ++i)
                {
                    ((CheckBox)standardOfCareList[i]).Checked = true;
                }
            }
            else
            {
                for (int i = 0; i < standardOfCareList.Count; ++i)
                {
                    ((CheckBox)standardOfCareList[i]).Checked = false;
                }

            }
            if (selectAllReq.Checked)
            {
                for (int i = 0; i < requiredList.Count; ++i)
                {
                    ((CheckBox)requiredList[i]).Checked = true;
                }
            }
            else
            {
                for (int i = 0; i < requiredList.Count; ++i)
                {
                    ((CheckBox)requiredList[i]).Checked = false;
                }
            }
        }

    }

    #region Class BudgetTaskControlDesigner
    /// <summary>
    /// Designer associated with the BudgetTaskControl control.
    /// </summary>
    /// <remarks>
    /// This class cannot be used directly.
    /// </remarks>
    public class BudgetTaskControlDesigner : ControlDesigner
    {
        #region Overrides
        /// <summary>
        /// Since the BudgetTaskControl control does not have any design-time visibility, the designer provides
        /// the type name of that control and the name of the instance.
        /// </summary>
        /// <returns>HTML representation of the BudgetTaskControl control</returns>
        public override string GetDesignTimeHtml()
        {
            return CreatePlaceHolderDesignTimeHtml();
        }
        #endregion
    }
    #endregion
}